package utils

import (
	"log"
	"net"
	"runtime"
)

//PrintPanicStack print stack when panic
func PrintPanicStack(extras ...interface{}) {
	if x := recover(); x != nil {
		log.Println(x)
		i := 0
		funcName, file, line, ok := runtime.Caller(i)
		for ok {
			log.Printf("frame %v:[func:%v,file:%v,line:%v]\n", i, runtime.FuncForPC(funcName).Name(), file, line)
			i++
			funcName, file, line, ok = runtime.Caller(i)
		}
		for k := range extras {
			log.Printf("EXRAS#%v DATA:%v\n", k, extras[k])
		}
	}
}

//LocalIP returns the non loopback local IP of the host
func LocalIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	for _, address := range addrs {
		// check the address type and if it is not a loopback the display it
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				return ipnet.IP.String()
			}
		}
	}
	return ""
}

//DiffSlice diff the two slice, and return the differents
func DiffSlice(a, b []string) (ina, inb []string) {
	ma := make(map[string]struct{})
	mb := make(map[string]struct{})
	for i := range a {
		ma[a[i]] = struct{}{}
	}
	for i := range b {
		mb[b[i]] = struct{}{}
	}

	//in a, not in b.
	for k := range ma {
		if _, ok := mb[k]; !ok {
			ina = append(ina, k)
		}
	}
	//in b , not in a.
	for k := range mb {
		if _, ok := ma[k]; !ok {
			inb = append(inb, k)
		}
	}
	return
}
